package com.hs.monitor.message;

import com.hs.monitor.App;
import com.hs.monitor.encrypt.AESEncrypt;
import com.hs.monitor.encrypt.RSAEncrypt;
import com.hs.monitor.entity.MessageEntity;
import com.hs.monitor.utils.*;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

import static com.hs.monitor.entity.Code.*;
import static com.hs.monitor.utils.ByteUtil.getRandom;
import static com.hs.monitor.utils.ByteUtil.intToBytes;

public class Receiver {
    public static Map<Byte, Consumer<byte[]>> map = new HashMap<>();

    /**
     * RSA公钥,从服务器获取
     */
    private static byte[] rsa_publicKey;//rsa公钥

    private static byte[] aes_key = "u-will-be-better".getBytes(StandardCharsets.UTF_8); // 16字节的密钥
    private static byte[] aes_iv = "u-will-be-better".getBytes(StandardCharsets.UTF_8); //16字节的初始向量,必须16字节

    static {
        map.put(LOGIN_RES, Receiver::handle0x02);
        map.put(HEARTBEAT_RES, Receiver::handle0x04);
        map.put(CHARGING, Receiver::handle0x22);
    }

    public static void receive(byte[] msg) {
        Consumer<byte[]> consumer = map.get(msg[2]);
        if (consumer != null) {
            consumer.accept(msg);
        } else {
//            System.out.println("没有对应的数据帧");
            LogUtil.log("没有对应的数据帧");
        }
    }

    /**
     * 处理平台下发的02帧,其他帧类似
     *
     * @param bytes
     */
    public static void handle0x02(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        byte[] prefix = buffer.getBytes(7); //一条数据的固定前缀,后面的才是真正的数据
        //获取公钥,一帧数据前缀的长度为7,crc长度为2,剩余即为公钥长度
        byte[] key_bytes = buffer.getBytes(bytes.length - 7 - 2);
        byte[] crc_bytes = buffer.getBytes(2);

        byte[] crc_calc = CrcUtil.crc16(key_bytes);

        if (ByteUtil.bytesToInt(crc_bytes) != ByteUtil.bytesToInt(crc_calc)) {
            //获取的crc不等于本地计算的crc
//            System.out.println("crc_bytes=" + ByteUtil.bytesToHex(crc_bytes));
//            System.out.println("crc_calc=" + ByteUtil.bytesToHex(crc_calc));
            throw new RuntimeException("crc有误");
        }
        rsa_publicKey = key_bytes;

        res0x03();
    }

    /**
     * 回复03数据帧,
     * 回03,带sn,带key,带iv
     */
    public static void res0x03() {
        String sn = App.sn.getText();
        byte[] sn_bytes = sn.getBytes(StandardCharsets.UTF_8);
        //明文数据
        byte[] data_plain = ByteUtil.mergeBytes(sn_bytes, aes_key, aes_iv);

        //密文数据
        byte[] data_cipher = RSAEncrypt.encrypt(rsa_publicKey, data_plain);


        MessageEntity entity = MessageEntity.builder().functionCode(HEARTBEAT).frameNumber(intToBytes(0)).data(data_cipher).build();
        byte[] msg = MessageEntity.getBytes(entity);

        Sender.send(msg);

    }

    public static void handle0x04(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        byte[] prefix = buffer.getBytes(7); //一条数据的固定前缀,后面的才是真正的数据
        //获取公钥,一帧数据前缀的长度为7,sn长度为13,crc长度为2,剩余即为公钥长度
        byte[] result = buffer.getBytes(1);
        byte[] crc_bytes = buffer.getBytes(2);

        byte[] crc_calc = CrcUtil.crc16(result);

        if (ByteUtil.bytesToInt(crc_bytes) != ByteUtil.bytesToInt(crc_calc)) {
            //获取的crc不等于本地计算的crc
            throw new RuntimeException("crc有误");
        }

        if (result[0] == 0x01) {
            LogUtil.log("握手成功,开始正常发送数据");
            res0x11();
            heartbeat();
//            System.out.println("握手成功,开始正常发送数据");
        }
    }


    public static boolean isStop = false;

    //每次心跳带上sn
    public static void heartbeat() {
        AtomicInteger frameNumber = new AtomicInteger();
        TaskUtil.getExecutor().execute(() -> {
            while (!isStop) {
                byte[] sn_bytes = App.sn.getText().getBytes(StandardCharsets.UTF_8);
                LocalDateTime now = LocalDateTime.now();

                try {
                    //1分钟上报一次
                    TimeUnit.SECONDS.sleep(60);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //密文数据
                byte[] data_cipher = RSAEncrypt.encrypt(rsa_publicKey, sn_bytes);

                MessageEntity entity = MessageEntity.builder().functionCode(HEARTBEAT).frameNumber(ByteUtil.intToBytes(frameNumber.incrementAndGet())).data(data_cipher).build();
                byte[] msg = MessageEntity.getBytes(entity);
                Sender.send(msg);
            }
        });
    }

    public static void res0x11() {
        AtomicInteger frameNumber = new AtomicInteger();
        TaskUtil.getExecutor().execute(() -> {
            while (!isStop) {
                byte[] sn_bytes = App.sn.getText().getBytes(StandardCharsets.UTF_8);
                LocalDateTime now = LocalDateTime.now();

                int year = now.getYear() - 2000;
                int month = now.getMonthValue();
                int day = now.getDayOfMonth();

                int hour = now.getHour();
                int minute = now.getMinute();
                int second = now.getSecond();

                System.out.println("year=" + year);
                System.out.println("month=" + month);
                System.out.println("day=" + day);
                System.out.println("hour=" + hour);
                System.out.println("minute=" + minute);
                System.out.println("second=" + second);

                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                int vol_out = getRandom(2200, 20);
                int cur_in = getRandom(0, 20);
                int cur_out = getRandom(0, 20);
                int fre_in = 500;
                int fre_out = 500;
                int vol_in = getRandom(2200, 20);

                int cha_time = getRandom(20, 50);
                int cha_energy = getRandom(1, 40);


                byte[] vol_in_bytes = intToBytes(vol_in);
                byte[] vol_out_bytes = intToBytes(vol_out);
                byte[] cur_in_bytes = intToBytes(cur_in);
                byte[] cur_out_bytes = intToBytes(cur_out);
                byte[] fre_in_bytes = intToBytes(fre_in);
                byte[] fre_out_bytes = intToBytes(fre_out);
                byte[] cha_time_bytes = intToBytes(cha_time);
                byte[] cha_energy_bytes = intToBytes(cha_energy);

                //明文
                byte[] data_plain = ByteUtil.mergeBytes(sn_bytes, year, month, day, hour, minute, second, vol_in_bytes, vol_out_bytes, cur_in_bytes, cur_out_bytes, fre_in_bytes, fre_out_bytes, cha_time_bytes, cha_energy_bytes);

                //密文
                byte[] data_cipher = AESEncrypt.encrypt(aes_key, aes_iv, data_plain);


                MessageEntity entity = MessageEntity.builder().functionCode(REAL_DATA).frameNumber(ByteUtil.intToBytes(frameNumber.incrementAndGet())).data(data_cipher).build();
                byte[] msg = MessageEntity.getBytes(entity);
                Sender.send(msg);
            }
        });
    }

    public static void handle0x22(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        byte[] prefix = buffer.getBytes(7); //一条数据的固定前缀,后面的才是真正的数据
        byte[] result = buffer.getBytes(1);
        byte[] crc_bytes = buffer.getBytes(2);

        byte[] crc_calc = CrcUtil.crc16(result);

        if (ByteUtil.bytesToInt(crc_bytes) != ByteUtil.bytesToInt(crc_calc)) {
            //获取的crc不等于本地计算的crc
            throw new RuntimeException("crc有误");
        }
        if (result[0] == 0x01) {
            LogUtil.log_ctrl("...开始充电...");
        } else if (result[0] == 0x00) {
            LogUtil.log_ctrl("...停止充电...");
        }
    }

    public static void handle0x24(byte[] bytes) {
        LogUtil.log("...停止充电...");
    }
}
